﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Navigation;
using QuizzMe.Helpers;
using QuizzMe.Model;
using QuizzMe.QuizzServiceRef;

namespace QuizzMe.Pages
{
    /// <summary>
    /// Quizz page
    /// </summary>
    public partial class Quizz : BasePage
    {
        /// <summary>
        /// Quizz type : random, thematic, specific or defy
        /// </summary>
        public enum QuizzType
        {
            Random,
            Thematic,
            Specific,
            Defy
        }

        /// <summary>
        /// Answer of question
        /// </summary>
        public class Answer
        {
            public bool GoodAnswer { get; set; }

            public string Text { get; set; }

            public Answer(string text, bool right = false)
            {
                Text = text;
                GoodAnswer = right;
            }
        }

        /// <summary>
        /// Question model
        /// </summary>
        public class QuestionModel
        {
            public List<Answer> Answers;
            public string Text { get; set; }
            public int Time { get; set; }

            public QuestionModel(string text, int time)
            {
                Answers = new List<Answer>();
                Text = text;
                Time = time;
            }
        }

        private event Action TimesUpEvent;

        private int _time;
        private int _timespend;
        private int _maxtime;

        private ObservableCollection<CheckableText> _answersDisplayList;
        private Timer _timer;

        private QuizzServiceRef.Quizz _currentQuizz;
        private int _currentQuestion;
        private List<QuestionModel> _questions;
        private string _quizzTheme;
        private string _quizzInfos;

        private int _score;
        private int _goodAnswersNumber;
        private int _badAnswersNumber;
        private int _skipAnswersNumber;
        private bool _canAnswer;
        private QuestionModel _currentQuestionModel;

        // Type
        private QuizzType _type;
        private Result _typeResult;

        public ObservableCollection<CheckableText> AnswersDisplayList
        {
            get { return _answersDisplayList; }
            set { _answersDisplayList = value; }
        }

        public int Time
        {
            get { return _time; }
            set
            {
                if (_time != value)
                {
                    _time = value;
                    TimeSpend = MaxTime - Time;
                    OnPropertyChanged("Time");
                }
            }
        }

        public int TimeSpend
        {
            get { return _timespend; }
            set
            {
                if (_timespend != value)
                {
                    _timespend = value;
                    OnPropertyChanged("TimeSpend");
                }
            }
        }
        
        public int MaxTime
        {
            get { return _maxtime; }
            set
            {
                if (_maxtime != value)
                {
                    _maxtime = value;
                    OnPropertyChanged("MaxTime");
                }
            }
        }

        public bool CanAnswer
        {
            get { return _canAnswer; }
            set
            {
                if (_canAnswer != value)
                {
                    _canAnswer = value;
                    OnPropertyChanged("CanAnswer");
                }
            }
        }

        public int CurrentQuestion
        {
            get { return _currentQuestion; }
            set
            {
                if (_currentQuestion != value)
                {
                    _currentQuestion = value;

                    if (_currentQuestion >= 0 && _currentQuestion < _questions.Count)
                        CurrentQuestionModel = _questions[_currentQuestion];

                    OnPropertyChanged("CurrentQuestion");
                    OnPropertyChanged("CurrentQuestionIndex");
                    OnPropertyChanged("CurrentProgress");
                }
            }
        }

        public QuestionModel CurrentQuestionModel
        {
            get { return _currentQuestionModel; }
            set
            {
                if (_currentQuestionModel != value)
                {
                    _currentQuestionModel = value;
                    OnPropertyChanged("CurrentQuestionModel");
                }
            }
        }
        
        public string QuizzTheme
        {
            get { return _quizzTheme; }
            set
            {
                if (_quizzTheme != value)
                {
                    _quizzTheme = value;
                    OnPropertyChanged("QuizzTheme");
                }
            }
        }
        
        public string QuizzInfos
        {
            get { return _quizzInfos; }
            set
            {
                if (_quizzInfos != value)
                {
                    _quizzInfos = value;
                    OnPropertyChanged("QuizzInfos");
                }
            }
        }

        public int CurrentQuestionIndex
        {
            get { return _currentQuestion + 1; }
        }

        public string CurrentProgress
        {
            get
            {
                if (_questions == null)
                    return "null";
                return string.Format("Question {0} / {1}", CurrentQuestionIndex, _questions.Count);
            }
        }

        public Quizz()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs navigationEventArgs)
        {
            _score = 0;
            _goodAnswersNumber = 0;
            _badAnswersNumber = 0;
            _skipAnswersNumber = 0;

            AnswersDisplayList = new ObservableCollection<CheckableText>();

            MaxTime = 100;
            TimeSpend = 0;

            InitQuestions();

            TimesUpEvent += QuizzTimesUpEvent;

            _timer = new Timer(TimeDecrease, null, 1000, 1000);

            base.OnNavigatedTo(navigationEventArgs);
        }

        public void InitQuestions()
        {
            Loading = true;
            
            if (NavigationContext.QueryString.ContainsKey("theme"))
            {
                _type = QuizzType.Thematic;

                int id = int.Parse(NavigationContext.QueryString["theme"]);
                ServiceClientHelper.Client.GetQuizzByThemeIdCompleted += OnGetQuizzByThemeIdCompleted;
                ServiceClientHelper.Client.GetQuizzByThemeIdAsync(id);
            }
            else if(NavigationContext.QueryString.ContainsKey("id"))
            {
                _type = QuizzType.Specific;

                int id = int.Parse(NavigationContext.QueryString["id"]);
                ServiceClientHelper.Client.GetSpecificQuizzCompleted += OnGetSpecificQuizzCompleted;
                ServiceClientHelper.Client.GetSpecificQuizzAsync(id);
            }
            else if (NavigationContext.QueryString.ContainsKey("defy"))
            {
                _type = QuizzType.Defy;

                int id = int.Parse(NavigationContext.QueryString["defy"]);
                ServiceClientHelper.Client.GetResultCompleted += OnGetResultCompleted;
                ServiceClientHelper.Client.GetResultAsync(id);
            }
            else
            {
                _type = QuizzType.Random;
                
                ServiceClientHelper.Client.GetRandomQuizzCompleted += OnGetRandomQuizzCompleted;
                ServiceClientHelper.Client.GetRandomQuizzAsync();
            }
        }

        private void OnGetResultCompleted(object sender, GetResultCompletedEventArgs e)
        {
            ServiceClientHelper.Client.GetResultCompleted -= OnGetResultCompleted;

            _typeResult = e.Result;
            GetQuizzCompleted(e.Result.Quizz);

            QuizzInfos = "Defy against " + _typeResult.User.userName;
        }

        private void OnGetSpecificQuizzCompleted(object sender, GetSpecificQuizzCompletedEventArgs e)
        {
            ServiceClientHelper.Client.GetSpecificQuizzCompleted -= OnGetSpecificQuizzCompleted;
            GetQuizzCompleted(e.Result);
        }

        private void OnGetQuizzByThemeIdCompleted(object o, GetQuizzByThemeIdCompletedEventArgs args)
        {
            ServiceClientHelper.Client.GetQuizzByThemeIdCompleted -= OnGetQuizzByThemeIdCompleted;
            GetQuizzCompleted(args.Result);
        }

        private void OnGetRandomQuizzCompleted(object o, GetRandomQuizzCompletedEventArgs args)
        {
            ServiceClientHelper.Client.GetRandomQuizzCompleted -= OnGetRandomQuizzCompleted;
            GetQuizzCompleted(args.Result);
        }

        private void GetQuizzCompleted(QuizzServiceRef.Quizz quizz)
        {
            _currentQuizz = quizz;

            QuizzTheme = _currentQuizz.Theme.name;

            _questions = new List<QuestionModel>();
            foreach (QuizzPart quizzPart in quizz.QuizzParts)
            {
                QuestionModel model = new QuestionModel(quizzPart.Question.text, quizzPart.Question.time);
                model.Answers.AddRange(quizzPart.GetAnswers());

                _questions.Add(model);
            }
            CurrentQuestion = -1;

            NextQuestion();
            Loading = false;
        }

        public void TimeDecrease(Object state)
        {
            if (Time > 0)
            {
                Dispatcher.BeginInvoke(() =>
                                           {
                                               --Time;
                                               if (Time > 0)
                                                   return;

                                               if (_timer != null)
                                               {
                                                   _timer.Dispose();
                                                   _timer = null;
                                               }

                                               if (TimesUpEvent != null)
                                                   TimesUpEvent();
                                           });
            }
        }

        public bool NextQuestion()
        {
            if (_timer != null)
            {
                _timer.Dispose();
                _timer = null;
            }

            if ((CurrentQuestion + 1) < _questions.Count)
            {
                ++CurrentQuestion;

                AnswersDisplayList.Clear();
                foreach (Answer answer in _questions[CurrentQuestion].Answers)
                {
                    AnswersDisplayList.Add(new CheckableText(answer.Text));
                }

                if (AnswersDisplayList.Count > 0)
                    AnswersDisplayList[0].Selected = true;

                CanAnswer = true;
                MaxTime = _questions[CurrentQuestion].Time; 
                Time = _questions[CurrentQuestion].Time;
                TimeSpend = 0;

                _timer = new Timer(TimeDecrease, null, 1000, 1000);
                return true;
            }
            return false;
        }

        private void ButtonNextClick(object sender, RoutedEventArgs e)
        {
            CheckableText selectedDisplayAnswer = AnswersDisplayList.FirstOrDefault(a => a.Selected);
            if (selectedDisplayAnswer == null)
                return;

            Answer selectedAnswer = _questions[CurrentQuestion].Answers.FirstOrDefault(a => a.Text.Equals(selectedDisplayAnswer.Text));
            if (selectedAnswer == null)
                return;

            if (selectedAnswer.GoodAnswer)
            {
                _goodAnswersNumber += 1;
            }
            else
            {
                _badAnswersNumber += 1;
            }

            if (!NextQuestion())
            {
                SaveResult();
            }
        }

        private void ButtonPassClick(object sender, RoutedEventArgs e)
        {
            _skipAnswersNumber += 1;

            if (!NextQuestion())
            {
                SaveResult();
            }
        }

        private void SaveResult()
        {
            QuizzServiceRef.Difficulty difficulty = AuthHelper.Get.CurrentUser.User.Difficulty;
            _score = _goodAnswersNumber * difficulty.points_good +
                     _badAnswersNumber * difficulty.points_bad +
                     _skipAnswersNumber * difficulty.points_skip;

            Loading = true;
            ServiceClientHelper.Client.SaveResultCompleted += ClientSaveResultCompleted;
            ServiceClientHelper.Client.SaveResultAsync(AuthHelper.Get.CurrentUser.User.userId, _currentQuizz.quizzId, _score, _goodAnswersNumber, _badAnswersNumber, _skipAnswersNumber);
        }

        void ClientSaveResultCompleted(object sender, SaveResultCompletedEventArgs e)
        {
            AuthHelper.Get.RefreshUser(extendedUser =>
            {
                Loading = false;

                string argsPath = "/QuizzResult?r=" + e.Result;
                if (_type == QuizzType.Defy)
                {
                    argsPath += "&defy=" + _typeResult.resultId;
                }

                this.NavigateTo(argsPath);
            });
            ServiceClientHelper.Client.SaveResultCompleted -= ClientSaveResultCompleted;
        }

        public void QuizzTimesUpEvent()
        {
            Dispatcher.BeginInvoke(() => CanAnswer = false);
        }
    }
}
